package com.fm.structure.list;

import java.util.Iterator;

/**
 * @param <V>
 * @author finalmachine
 */
public class DoubleLinkedList<V> {
    private DoubleLinkedNode<V> head;
    private DoubleLinkedNode<V> tail;
    private int size = 0;

    public int size() {
        return size;
    }

    public void add(V value) {
        if (tail == null) {
            head = tail = new DoubleLinkedNode<>(value, null, null);
        } else {
            DoubleLinkedNode<V> temp = new DoubleLinkedNode<>(value, tail, null);
            tail.setNext(temp);
            tail = temp;
        }
        size++;
    }

    public DoubleLinkedNode<V> getHead() {
        return head;
    }

    public DoubleLinkedNode<V> getTail() {
        return tail;
    }

    public void remove(DoubleLinkedNode<V> node) {
        DoubleLinkedNode<V> prev = node.getPrev();
        DoubleLinkedNode<V> next = node.getNext();
        if (prev == null) {
            if (next == null) {
                head = tail = null;
            } else {
                next.setPrev(null);
                head = next;
            }
        } else {
            if (next == null) {
                prev.setNext(null);
                tail = prev;
            } else {
                prev.setNext(node.getNext());
                next.setPrev(node.getPrev());
            }
        }
        size--;
    }

    public void tail(DoubleLinkedNode<V> node) {
        node.setNext(null);
        tail = node;
    }

    public void clear() {
        head = tail = null;
        size = 0;
    }

    public Iterator<V> iterator() {
        return new Iterator<>() {
            DoubleLinkedNode<V> pre;
            DoubleLinkedNode<V> cur = head;

            @Override
            public boolean hasNext() {
                return cur != null;
            }

            @Override
            public V next() {
                try {
                    return cur.getValue();
                } finally {
                    pre = cur;
                    cur = cur.getNext();
                }
            }

            @Override
            public void remove() {
                DoubleLinkedList.this.remove(pre);
            }
        };
    }
}
